package com.greenline.push.services;

import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.alibaba.fastjson.JSON;
import com.greenline.push.core.enums.ClassMessageStatus;
import com.greenline.push.core.enums.MsgSendType;
import com.greenline.push.core.pushcenter.ClassDefineManager;
import com.greenline.push.core.pushcenter.ClassMessageManager;
import com.greenline.push.core.pushcenter.DomainManager;
import com.greenline.push.core.pushcenter.GroupManager;
import com.greenline.push.core.pushcenter.GroupUserManager;
import com.greenline.push.core.pushcenter.TemplateManager;
import com.greenline.push.dal.pushcenter.dataobject.ClassDefineDO;
import com.greenline.push.dal.pushcenter.dataobject.ClassMessageDO;
import com.greenline.push.dal.pushcenter.dataobject.DomainDO;
import com.greenline.push.dal.pushcenter.dataobject.GroupDO;
import com.greenline.push.dal.pushcenter.dataobject.GroupUserDO;
import com.greenline.push.service.core.IProcessor;
import com.greenline.push.service.core.item.Packet;
import com.greenline.push.service.core.tmpl.AppTemplateCache;
import com.greenline.push.service.core.tmpl.AppTemplateInfo;
import com.greenline.push.service.core.tmpl.TemplateCache;
import com.greenline.push.service.core.tmpl.TemplateInfo;
import com.greenline.push.service.core.utils.Constants;
import com.greenline.push.services.PushCenterCommonService;
import com.greenline.push.services.dto.ResponseCode;
import com.greenline.push.services.dto.ResponseDTO;

public class PushCenterCommonServiceImpl implements PushCenterCommonService {
    @Resource
    private IProcessor processer;
    @Resource
    private TemplateCache template;
    private Logger logger = Constants.LOG_DUBBO;
    @Resource
    private GroupManager groupManager;
    @Resource
    private GroupUserManager guserManager;
    @Resource
    private AppTemplateCache appTemplateCache;
    @Resource
    private DomainManager domainManager;
    @Resource
    private TemplateManager templateManager;
    @Resource
    private ClassDefineManager classManager;
    @Resource
    private ClassMessageManager classMessageManager;

    @Override
    public ResponseDTO<String> getBizDefine(String templateCode) {
        ResponseDTO<String> rResonse = new ResponseDTO<String>();
        logger.info(String.format("{getBizDefine} push服务收到获取模板定义请求.模板code：%s", templateCode));
        TemplateInfo s = template.getByCode(templateCode);
        if (null == s) {
            rResonse.setDataResult(null);
            rResonse.setCode(ResponseCode.ERROR);
            rResonse.setErrorMsg("未找到模版");
            return rResonse;
        } else {
            rResonse.setDataResult(s.getText());
            rResonse.setCode(ResponseCode.SUCCESS);
            rResonse.setMessage("查询成功");
            return rResonse;
        }
    }

    @Override
    public ResponseDTO<Boolean> send(Long receiverUserId, String templateCode, String domainCode, Map<String, String> param, Long sendTime) {
        ResponseDTO<Boolean> rResonse = new ResponseDTO<Boolean>();
        logger.info(String.format("{send}push服务收到请求接受者%s模板code:%s,domaincode:%s", receiverUserId, templateCode, domainCode));
        TemplateInfo templateInfo = template.getByCode(templateCode);
        String domainId = getDomainId(domainCode);
        String templateId = getTemplateId(templateCode);
        /**
         * domainId templateId
         */
        if (null == domainId || null == templateId) {
            logger.error(String.format("{send}push 服务出错.code对应的id存在空值,domainId:%s,templateId:%s", domainId, templateId));
            rResonse.setCode(ResponseCode.PARAMETER_ERROR);
            rResonse.setDataResult(false);
            rResonse.setErrorMsg("templateCode或domainCode无效");
            return rResonse;
        }

        List<AppTemplateInfo> appTemplateList = appTemplateCache.get(Long.parseLong(templateId), Long.parseLong(domainId));
        // valid
        rResonse = checkParams(templateId, domainId, param, templateInfo, appTemplateList);

        /**
         * 如果参数校验不成功，直接返回
         */
        if (rResonse.getCode() != ResponseCode.SUCCESS) {
            return rResonse;
        }
        /**
         * 打包
         */
        Packet packet = new Packet();
        packet.setTemplateId(Long.parseLong(templateId));
        packet.setParam(param);
        packet.setPriority(templateInfo.getPriority());
        packet.setRecvUserId(receiverUserId);
        packet.setType(MsgSendType.POINT.getType());
        packet.setDomainId(Long.valueOf(domainId));
        packet.setSendingTime(sendTime);
        /**
         * 发送队列
         */
        processer.process(packet);
        rResonse.setCode(ResponseCode.SUCCESS);
        rResonse.setDataResult(true);
        rResonse.setMessage("发送成功");
        return rResonse;

    }

    @Override
    public ResponseDTO<Boolean> sendGroup(Long gid, String templateCode, String domainCode, Map<String, String> param, Long sendTime) {
        ResponseDTO<Boolean> rResonse = new ResponseDTO<Boolean>();
        logger.info(String.format("{sendGroup}push 收到群发请求。gid:%s.templateCode:%s,domainCode:%s", gid, templateCode, domainCode));
        TemplateInfo templateInfo = template.getByCode(templateCode);
        String domainId = getDomainId(domainCode);
        String templateId = getTemplateId(templateCode);
        /**
         * domainId templateId
         */
        if (null == domainId || null == templateId) {
            logger.error(String.format("{sendGroup}push 服务出错.code对应的id存在空值,domainId:%s,templateId:%s", domainId, templateId));
            rResonse.setCode(ResponseCode.PARAMETER_ERROR);
            rResonse.setDataResult(false);
            rResonse.setErrorMsg("templateCode或domainCode无效");
            return rResonse;
        }

        List<AppTemplateInfo> domainList = appTemplateCache.get(Long.parseLong(templateCode), Long.parseLong(domainCode));
        // valid
        rResonse = checkParams(templateId, domainId, param, templateInfo, domainList);
        /**
         * 如果参数校验不成功，直接返回
         */
        if (rResonse.getCode() != ResponseCode.SUCCESS) {
            return rResonse;
        }

        /**
         * 打包
         */
        Packet packet = new Packet();
        packet.setTemplateId(Long.parseLong(templateId));
        packet.setParam(param);
        packet.setPriority(templateInfo.getPriority());
        packet.setRecvUserId(gid);
        packet.setType(MsgSendType.GROUP.getType());
        packet.setDomainId(Long.valueOf(domainId));
        packet.setSendingTime(sendTime);
        /**
         * 发送队列
         */
        processer.process(packet);
        rResonse.setCode(ResponseCode.SUCCESS);
        rResonse.setDataResult(true);
        rResonse.setMessage("发送成功");
        return rResonse;
    }

    @Override
    public ResponseDTO<Boolean> createBroadCast(String classCode, String templateCode, String domainCode, Map<String, String> param,
            Long sendTime) {
        ResponseDTO<Boolean> rResonse = new ResponseDTO<Boolean>();
        logger.info(String.format("{createBroadCast}push服务收到请求 模板code:%s,domaincode:%s,classCode:%s", templateCode, domainCode, classCode));
        TemplateInfo templateInfo = template.getByCode(templateCode);
        String domainId = getDomainId(domainCode);
        String templateId = getTemplateId(templateCode);
        /**
         * domainId templateId
         */
        if (null == domainId || null == templateId) {
            logger.error(String.format("{createBroadCast}push 服务出错.code对应的id存在空值,domainId:%s,templateId:%s", domainId, templateId));
            rResonse.setCode(ResponseCode.PARAMETER_ERROR);
            rResonse.setDataResult(false);
            rResonse.setErrorMsg("templateCode或domainCode无效");
            return rResonse;
        }

        List<AppTemplateInfo> appTemplateList = appTemplateCache.get(Long.parseLong(templateId), Long.parseLong(domainId));
        // valid
        rResonse = checkParams(templateId, domainId, param, templateInfo, appTemplateList);
        /**
         * 如果参数校验不成功，直接返回
         */
        if (rResonse.getCode() != ResponseCode.SUCCESS) {
            return rResonse;
        }
        ClassDefineDO classresult = classManager.getByCode(classCode);
        if (null == classresult) {
            rResonse.setCode(ResponseCode.ERROR);
            rResonse.setErrorMsg("不存在组");
            rResonse.setDataResult(false);
            return rResonse;
        }
        Integer messgageType = classresult.getType();
        /**
         * create message
         * 
         */
        ClassMessageDO message = new ClassMessageDO();
        message.setMemo("广播消息");
        message.setType(MsgSendType.getMsgType(messgageType).getType());
        message.setDomainCode(domainCode);
        message.setTemplateCode(templateCode);
        message.setClassCode(classCode);
        message.setClassId(classresult.getId());
        message.setStatus(ClassMessageStatus.WAIT_PUSH.getStatus());
        message.setContent(param.toString());
        Long messageId;
        try {
            messageId = classMessageManager.insert(message);
        } catch (Exception e) {
            logger.error(String.format("{createBroadCast}消息入库失败.原因:%s", e.getMessage()));
            rResonse.setCode(ResponseCode.ERROR);
            rResonse.setErrorMsg(e.getMessage());
            rResonse.setDataResult(false);
            return rResonse;
        }
        /**
         * 打包
         */
        Packet packet = new Packet();
        packet.setTemplateId(Long.parseLong(templateId));
        packet.setParam(param);
        packet.setPriority(templateInfo.getPriority());
        packet.setType(classresult.getType());
        packet.setDomainId(Long.valueOf(domainId));
        packet.setMessageId(messageId);
        packet.setClassId(classresult.getId());
        packet.setSendingTime(sendTime);
        /**
         * return
         */
        processer.process(packet);
        rResonse.setCode(ResponseCode.SUCCESS);
        rResonse.setDataResult(true);
        rResonse.setMessage("发送成功");
        return rResonse;
    }

    @Override
    public ResponseDTO<Boolean> sendDomain(String templateCode, String domainCode, Map<String, String> param, Long sendTime) {
        ResponseDTO<Boolean> rResonse = new ResponseDTO<Boolean>();
        logger.info(String.format("{sendDomain}push服务收到域推送请求.模板code:%s,域code:%s", templateCode, domainCode));
        TemplateInfo templateInfo = template.getByCode(templateCode);
        String domainId = getDomainId(domainCode);
        String templateId = getTemplateId(templateCode);
        /**
         * domainId templateId
         */
        if (null == domainId || null == templateId) {
            logger.error(String.format("{sendDomain}push 服务出错.code对应的id存在空值,domainId:%s,templateId:%s", domainId, templateId));
            rResonse.setCode(ResponseCode.PARAMETER_ERROR);
            rResonse.setDataResult(false);
            rResonse.setErrorMsg("templateCode或domainCode无效");
            return rResonse;
        }
        List<AppTemplateInfo> apptemplateInfolist = appTemplateCache.get(Long.parseLong(templateId), Long.parseLong(domainId));
        // valid
        rResonse = checkParams(templateId, domainId, param, templateInfo, apptemplateInfolist);
        /**
         * 如果参数校验不成功，直接返回
         */
        if (rResonse.getCode() != ResponseCode.SUCCESS) {
            return rResonse;
        }

        /**
         * create message
         * 
         */
        ClassMessageDO message = new ClassMessageDO();
        message.setMemo("域发送消息");
        message.setType(MsgSendType.DOMAIN.getType());
        message.setDomainCode(domainCode);
        message.setTemplateCode(templateCode);
        message.setStatus(ClassMessageStatus.WAIT_PUSH.getStatus());
        Long messageId = classMessageManager.insert(message);
        /**
         * 打包
         */
        Packet packet = new Packet();
        packet.setTemplateId(Long.parseLong(templateId));
        packet.setParam(param);
        packet.setPriority(templateInfo.getPriority());
        packet.setType(MsgSendType.DOMAIN.getType());
        packet.setDomainId(Long.valueOf(domainId));
        packet.setMessageId(messageId);
        packet.setSendingTime(sendTime);
        /**
         * 发送队列
         */
        processer.process(packet);
        rResonse.setCode(ResponseCode.SUCCESS);
        rResonse.setDataResult(true);
        rResonse.setMessage("发送成功");
        return rResonse;
    }

    @Override
    public ResponseDTO<Boolean> sendDomains(String templateCodes, List<String> domainCodes, Map<String, String> param, Long sendTime) {
        logger.info(String.format("{sendDomains}push 收到多domain发送请求。domainIds:%s.templateId:%s", domainCodes, templateCodes));
        ResponseDTO<Boolean> sResult = null;
        /**
         * 如果有一个发生失败，则直接返回
         */
        for (String domainCode : domainCodes) {
            sResult = sendDomain(templateCodes, domainCode, param, sendTime);
            // not success
            if (!sResult.getCode().equalsIgnoreCase(ResponseCode.SUCCESS)) {
                return sResult;
            }
        }
        return sResult;
    }

    @Override
    public ResponseDTO<Boolean> sendList(List<Long> userList, String templateId, String domainId, Map<String, String> param, Long sendTime) {
        logger.info(String.format("push 收到集合发送请求。List:%s.templateId:%s,domainId:%s", JSON.toJSONString(userList), templateId, domainId));
        ResponseDTO<Boolean> sResult = null;
        /**
         * 如果有一个发生失败，则直接返回
         */
        for (Long userId : userList) {
            sResult = send(userId, templateId, domainId, param, sendTime);
            // not success
            if (!sResult.getCode().equalsIgnoreCase(ResponseCode.SUCCESS)) {
                return sResult;
            }
        }
        return sResult;
    }

    @Override
    public ResponseDTO<Long> createGroup(String groupName, Long ownerUserId) {
        logger.info(String.format("push 收到建群请求。gName:%s.ownId:%s", groupName, ownerUserId));
        ResponseDTO<Long> rResonse = new ResponseDTO<Long>();
        /**
         * 检查空值
         */
        if (null == ownerUserId || StringUtils.isBlank(groupName)) {
            rResonse.setDataResult(null);
            rResonse.setCode(ResponseCode.ERROR);
            rResonse.setMessage("建群失败，原因:参数有误，请检查类型或空值");
            return rResonse;
        }
        GroupDO gResult = groupManager.getByGName(groupName);
        /**
         * 检查重复名称
         */
        if (null != gResult) {
            rResonse.setDataResult(null);
            rResonse.setCode(ResponseCode.ERROR);
            rResonse.setMessage("建群失败，原因:群名称存在重复");
            return rResonse;
        }
        Long gid = null;
        try {
            GroupDO group = new GroupDO();
            group.setName(groupName);
            group.setOid(ownerUserId);
            gid = groupManager.insert(group);
            rResonse.setDataResult(gid);
            rResonse.setCode(ResponseCode.SUCCESS);
            rResonse.setMessage("建群成功");
        } catch (Exception e) {
            e.printStackTrace();
            rResonse.setDataResult(gid);
            rResonse.setCode(ResponseCode.ERROR);
            rResonse.setMessage("建群失败，原因:" + e.getMessage());
            logger.error("{createGroup}建群失败,异常:" + e.getMessage());
        }
        return rResonse;
    }

    @Override
    public ResponseDTO<Boolean> subscribe(Long groupId, Long userid) {
        logger.info(String.format("push 收到订阅请求。gid:%s.userid:%s", groupId, userid));
        ResponseDTO<Boolean> rResonse = new ResponseDTO<Boolean>();
        /**
         * 检查空值
         */
        if (null == groupId || null == userid) {
            rResonse.setDataResult(null);
            rResonse.setCode(ResponseCode.ERROR);
            rResonse.setMessage("订阅失败，原因:参数有误，请检查类型或空值");
            return rResonse;
        }

        try {
            GroupUserDO gudo = new GroupUserDO();
            gudo.setGroupId(groupId);
            gudo.setUserId(userid);
            guserManager.insert(gudo);
            rResonse.setDataResult(true);
            rResonse.setCode(ResponseCode.SUCCESS);
            rResonse.setMessage("订阅成功");
        } catch (Exception e) {
            e.printStackTrace();
            rResonse.setDataResult(false);
            rResonse.setCode(ResponseCode.ERROR);
            rResonse.setMessage("订阅失败，原因:" + e.getMessage());
            logger.error("{subscribe}订阅失败,异常:" + e.getMessage());
        }
        return rResonse;
    }

    /**
     * 批量订阅
     */
    @Override
    public ResponseDTO<Boolean> subscribe(Long groupId, List<Long> userids) {
        logger.info(String.format("push 收到订阅请求列表。gid:%s.userids:%s", groupId, userids));
        ResponseDTO<Boolean> rResonse = new ResponseDTO<Boolean>();
        /**
         * 检查空值
         */
        if (null == groupId || null == userids || userids.size() == 0) {
            rResonse.setDataResult(null);
            rResonse.setCode(ResponseCode.ERROR);
            rResonse.setMessage("订阅失败，原因:参数有误，请检查类型或空值");
            return rResonse;
        }

        try {
            for (Long userid : userids) {
                GroupUserDO gudo = new GroupUserDO();
                gudo.setGroupId(groupId);
                gudo.setUserId(userid);
                guserManager.insert(gudo);
                rResonse.setDataResult(true);
                rResonse.setCode(ResponseCode.SUCCESS);
                rResonse.setMessage("订阅成功");
            }
        } catch (Exception e) {
            e.printStackTrace();
            rResonse.setDataResult(false);
            rResonse.setCode(ResponseCode.ERROR);
            rResonse.setMessage("订阅失败，原因:" + e.getMessage());
            logger.error("{subscribelist}订阅失败,异常:" + e.getMessage());
        }
        return rResonse;
    }

    /**
     * 取消订阅
     */
    @Override
    public ResponseDTO<Boolean> unsubscribe(Long groupId, Long userid) {
        logger.info(String.format("push 收到取消订阅请求。gid:%s.userid:%s", groupId, userid));
        ResponseDTO<Boolean> rResonse = new ResponseDTO<Boolean>();
        /**
         * 检查空值
         */
        if (null == groupId || null == userid) {
            rResonse.setDataResult(null);
            rResonse.setCode(ResponseCode.ERROR);
            rResonse.setMessage("取消订阅失败，原因:参数有误，请检查类型或空值");
            return rResonse;
        }

        try {
            GroupUserDO gudo = new GroupUserDO();
            gudo.setGroupId(groupId);
            gudo.setUserId(userid);
            guserManager.delete(groupId, userid);
            rResonse.setDataResult(true);
            rResonse.setCode(ResponseCode.SUCCESS);
            rResonse.setMessage("取消订阅成功");
        } catch (Exception e) {
            e.printStackTrace();
            rResonse.setDataResult(false);
            rResonse.setCode(ResponseCode.ERROR);
            rResonse.setMessage("取消订阅失败，原因:" + e.getMessage());
            logger.error("{unsubscribe}取消订阅失败,异常:" + e.getMessage());
        }
        return rResonse;
    }

    private String getDomainId(String code) {
        DomainDO dtmp = domainManager.getByCode(code);
        if (dtmp != null)
            return dtmp.getId().toString();
        else
            return null;
    }

    private String getTemplateId(String code) {
        TemplateInfo s = template.getByCode(code);
        if (s != null)
            return s.getId().toString();
        else
            return null;
    }

    /**
     * valid
     * 
     * @param templateId
     * @param domainId
     * @param param
     * @param templateInfo
     * @param appTemplateinfoList
     * @return
     */
    private ResponseDTO<Boolean> checkParams(String templateId, String domainId, Map<String, String> param, TemplateInfo templateInfo,
            List<AppTemplateInfo> appTemplateinfoList) {
        ResponseDTO<Boolean> rResonse = new ResponseDTO<Boolean>();
        /**
         * 模板
         */
        if (null == templateInfo) {
            rResonse.setCode(ResponseCode.ERROR);
            rResonse.setDataResult(false);
            rResonse.setErrorMsg(String.format("模板id%s不存在", templateId));
            return rResonse;
        }
        /**
         * 应用模版检查
         */

        if (appTemplateinfoList == null || appTemplateinfoList.size() == 0) {
            rResonse.setCode(ResponseCode.ERROR);
            rResonse.setDataResult(false);
            rResonse.setErrorMsg(String.format("模版%s:域%s下不存在发送通道", templateId, domainId));
            return rResonse;
        }
        /**
         * 参数检查
         */
        String params = templateInfo.getParams();
        String[] paramArray = params.split(Constants.PARAMS_SEPARATOR);
        for (int i = 0; i < paramArray.length; i++) {
            if (StringUtils.isNotBlank(paramArray[i]) && !param.containsKey(paramArray[i])) {
                rResonse.setCode(ResponseCode.PARAMETER_ERROR);
                rResonse.setDataResult(false);
                rResonse.setErrorMsg(String.format("参数%s不可为空", paramArray[i]));
                return rResonse;
            }
        }
        return rResonse;
    }

}
